//桥接模式  Bridge Pattern
//将抽象部分与它的实现部门分离，使得他们都可以独立的进行变化
//类之间的关系，应该受限考虑  组合或者聚合  关系，其次才是继承关系
//组合或者聚合是一种相对较弱的耦合，而继承是一种强耦合关系  继承关系，是一种is a的关系
#include <iostream>
#include <memory>
#include <string>
#include <list>

class Software
{
public:
    using ptr = std::shared_ptr<Software>;
    virtual void operation() = 0;
};

class Player : public Software
{
public:
    using ptr = std::shared_ptr<Player>;
    virtual void operation() override
    {
        std::cout << "我是播放器，我能放音乐" << std::endl;
    }
};

class Game : public Software
{
public:
    using ptr = std::shared_ptr<Game>;
    virtual void operation() override
    {
        std::cout << "我是游戏，我超好玩的，快来呀！" << std::endl;
    }
};

class AddressBook : public Software
{
public:
    using ptr=std::shared_ptr<AddressBook>;
    virtual void operation() override
    {
        std::cout << "我是通讯录，我里面存了很多妹妹的电话~" << std::endl;
    }
};
//软件和手机都是虚类，两个虚类采用聚合产生关系，便属于桥接
//因为严格来讲，软件和手机并不是is a的关系，而更属于has a的关系，即手机中有很多软件
class AbstractPhone
{
public:
    using ptr=std::shared_ptr<AbstractPhone>;
    virtual void operation() = 0;
       void install(Software::ptr software)
    {
        m_softwares.push_back(software);
    }
    void uninstall(Software::ptr software)
    {
        m_softwares.remove(software);
    }
protected:
    std::list<Software::ptr> m_softwares;
};

class PhoneA:public AbstractPhone
{
public:
    using ptr=std::shared_ptr<PhoneA>;
 
    void operation()
    {
        std::cout<<"我是A手机,下面展示所有应用:"<<std::endl;
        for(const auto& item:AbstractPhone::m_softwares){
            item->operation();
        }
    }
private:
    
};

class PhoneB:public AbstractPhone
{
public:
    using ptr=std::shared_ptr<PhoneB>;
    void operation()
    {
        std::cout<<"我是B手机，下面展示所有应用"<<std::endl;
        for(const auto& item:AbstractPhone::m_softwares){
            item->operation();
        }
    }
};
//测试
int main()
{
    Player::ptr player(new Player);
    Game::ptr game(new Game);
    AddressBook::ptr addressBook(new AddressBook);
    PhoneA::ptr phoneA(new PhoneA);
    PhoneB::ptr phoneB(new PhoneB);
    phoneA->install(player);
    phoneA->install(game);
    phoneA->operation();
    phoneB->install(game);
    phoneB->install(addressBook);
    phoneB->operation();
    return 0;
}